package core

import (
	"encoding/binary"
	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
	"github.com/ipipdotnet/ipdb-go"
	"github.com/shirou/gopsutil/v3/process"
	"net"
	"strconv"
	"strings"
	"sync"
)

// 用于保存Ip 地址对应的host 作为缓存
var ipHost sync.Map

type Parser struct {
	devName string            `json:"-"`
	handle  *pcap.Handle      `json:"-"`
	message chan<- PacketInfo `json:"-"`
	db      *ipdb.City        `json:"-"`
}

// NewParser 创建解析器实例
func NewParser(devName string, handle *pcap.Handle, message chan<- PacketInfo, db *ipdb.City) *Parser {
	return &Parser{devName: devName, handle: handle, message: message, db: db}

}

// ParseNextPacket 解析下一个数据包(已弃用）
func (p *Parser) ParseNextPacket() (PacketInfo, error, bool) {
	data, _, err := p.handle.ReadPacketData()

	if err != nil {
		return PacketInfo{}, err, false
	}

	packet := gopacket.NewPacket(
		data,
		p.handle.LinkType(),
		gopacket.Default,
	)

	return p.parsePacket(packet), nil, true
}

// 解析连续数据源,该函数和ParseNextPacket 冲突
func (p *Parser) ParsePacketResource() {
	packetSource := gopacket.NewPacketSource(p.handle, p.handle.LinkType())

	// 针对每一个数据包开一个协程，将数据包的数据解析并且存储到json文件中
	packetsChan := packetSource.Packets()
	for {
		select {
		case packet, ok := <-packetsChan:
			if ok {
				go func(packet gopacket.Packet) {
					info := p.parsePacket(packet)
					p.message <- info
				}(packet)
			}
		case <-endChannel:
			return
		}
	}

}

// parsePacket 传入packet 数据包，解析数据包中的数据
func (p *Parser) parsePacket(packet gopacket.Packet) PacketInfo {
	info := PacketInfo{
		DeviceName: p.devName,
		Timestamp:  packet.Metadata().Timestamp,
		Metadata:   packet.Metadata(),
	}

	// 数据链路层 (MAC)
	if ethLayer := packet.Layer(layers.LayerTypeEthernet); ethLayer != nil {
		eth := ethLayer.(*layers.Ethernet)
		info.SrcMAC = eth.SrcMAC.String()
		info.DstMAC = eth.DstMAC.String()
	}

	// 网络层 (IP)
	ipLayer := packet.Layer(layers.LayerTypeIPv4)
	ip6Layer := packet.Layer(layers.LayerTypeIPv6)
	ifSrcIpParser := true
	ifDstIpParser := true
	switch {
	case ipLayer != nil:
		ip := ipLayer.(*layers.IPv4)
		info.SrcIP = ip.SrcIP.String()
		info.DstIP = ip.DstIP.String()
		info.Protocol = "IPv4"

	case ip6Layer != nil:
		ip := ip6Layer.(*layers.IPv6)
		info.SrcIP = ip.SrcIP.String()
		info.DstIP = ip.DstIP.String()
		info.Protocol = "IPv6"
	}
	if net.ParseIP(info.DstIP).IsPrivate() || net.ParseIP(info.DstIP).IsLoopback() || net.ParseIP(info.DstIP).IsLinkLocalMulticast() {
		ifDstIpParser = false
	}
	if net.ParseIP(info.SrcIP).IsPrivate() || net.ParseIP(info.SrcIP).IsLoopback() || net.ParseIP(info.SrcIP).IsLinkLocalMulticast() {
		ifSrcIpParser = false
	}
	// 解析ip
	if ifSrcIpParser {
		SrcIpData, err := p.db.FindMap(info.SrcIP, "CN")
		if err != nil {
			//fmt.Println("SrcIP not found")
		}
		info.SrcIPinfo = MapToInfo2Ipinfo(SrcIpData)
	}

	if ifDstIpParser {
		DstIpData, err := p.db.FindMap(info.DstIP, "CN")
		if err != nil {
			//fmt.Println("DstIP not found")
		}
		info.DstIPinfo = MapToInfo2Ipinfo(DstIpData)
	}

	// 传输层
	tcpLayer := packet.Layer(layers.LayerTypeTCP)
	udpLayer := packet.Layer(layers.LayerTypeUDP)
	icmpLayer := packet.Layer(layers.LayerTypeICMPv4)
	icmp6Layer := packet.Layer(layers.LayerTypeICMPv6)
	switch {
	case tcpLayer != nil:
		tcp := tcpLayer.(*layers.TCP)
		info.Protocol = "TCP"
		info.SrcPort = uint16(tcp.SrcPort)
		info.DstPort = uint16(tcp.DstPort)
	case udpLayer != nil:
		udp := udpLayer.(*layers.UDP)
		info.Protocol = "UDP"
		info.SrcPort = uint16(udp.SrcPort)
		info.DstPort = uint16(udp.DstPort)
	case icmpLayer != nil:
		info.Protocol = "ICMPv4"
	case icmp6Layer != nil:
		info.Protocol = "ICMPv6"
	}

	// 应用层数据
	if appLayer := packet.ApplicationLayer(); appLayer != nil {
		info.Payload = appLayer.Payload()
		info.PayloadLen = len(info.Payload)
		if (info.SrcPort == 80 || info.DstPort == 80) && (info.Protocol == "TCP") {
			host := parserApplicationHttp(info.DstIP, string(info.Payload))
			info.Host = host

		}

		if info.Protocol == "TCP" && (info.SrcPort == 443 || info.DstPort == 443) {
			host := parserApplicationHttps(info.DstIP, packet)
			info.Host = host

		}

	}
	singleProcess, ok := ipProcess.Load(info.SrcIP + ":" + strconv.Itoa(int(info.SrcPort)))
	if ok {
		// 判断是不是process 类型的
		if value, ok := singleProcess.(*process.Process); ok {
			name, _ := value.Name()
			info.ProcessName = name
		}
	}
	return info
}

func parserApplicationHttp(ip string, data string) string {
	if host, _ := ipHost.Load(ip); host == "" {
		return ""
	}

	// 分割请求行和头部
	parts := strings.SplitN(data, "\r\n", 2)
	if len(parts) < 2 {
		return ""
	}

	// 遍历头部行
	headers := parts[1]
	for _, line := range strings.Split(headers, "\r\n") {
		if strings.HasPrefix(line, "Host:") {
			// 提取Host值
			host := strings.TrimSpace(line[len("Host:"):])
			ipHost.Store(ip, host)
			return host
		}
	}

	return ""
}

func parserApplicationHttps(ip string, packet gopacket.Packet) string {

	if host, _ := ipHost.Load(ip); host == "" {
		return ""
	}

	//接下来也是从handShake 中提取 host,由于 pcap包中关于TLS 的解析太基础了，无法满足需求，这里采用直接从字节解析
	host := extractSNIFromPacket(packet)
	ipHost.Store(ip, host)
	return host
}

func extractSNIFromPacket(packet gopacket.Packet) string {
	// 获取TCP层
	tcpLayer := packet.Layer(layers.LayerTypeTCP)
	if tcpLayer == nil {
		return ""
	}

	tcp, _ := tcpLayer.(*layers.TCP)

	// 检查应用层数据长度
	payload := tcp.Payload
	if len(payload) < 5 { // TLS记录头至少5字节
		return ""
	}

	// 检查是否是TLS握手记录(0x16)
	if payload[0] != 0x16 {
		return ""
	}

	// 检查是否是ClientHello(握手类型0x01)
	if len(payload) < 6 || payload[5] != 0x01 {
		return ""
	}

	// 快速解析SNI扩展
	return parseSNIFromClientHello(payload[5:]) // 跳过TLS记录头
}

// 解析ClientHello 协议规定的内容
func parseSNIFromClientHello(data []byte) string {
	// ClientHello最小长度检查
	if len(data) < 2+32+1+2+1+2 {
		return ""
	}

	// 跳过:
	// 1(类型) + 3(长度) + 2(版本) + 32(随机数)
	// + 1(session_id长度) + session_id
	pos := 1 + 3 + 2 + 32 + 1 + int(data[1+3+2+32])

	// 跳过密码套件(2字节长度 + 套件列表)
	if len(data) < pos+2 {
		return ""
	}
	cipherSuitesLen := int(binary.BigEndian.Uint16(data[pos : pos+2]))
	pos += 2 + cipherSuitesLen

	// 跳过压缩方法(1字节长度 + 方法列表)
	if len(data) < pos+1 {
		return ""
	}
	compMethodsLen := int(data[pos])
	pos += 1 + compMethodsLen

	// 检查扩展长度
	if len(data) < pos+2 {
		return ""
	}
	extensionsLen := int(binary.BigEndian.Uint16(data[pos : pos+2]))
	pos += 2

	// 解析扩展
	endPos := pos + extensionsLen
	for pos < endPos && pos+4 <= len(data) {
		extType := int(binary.BigEndian.Uint16(data[pos : pos+2]))
		extLen := int(binary.BigEndian.Uint16(data[pos+2 : pos+4]))
		pos += 4

		// 检查是否是SNI扩展(类型0)
		if extType == 0 {
			if len(data) < pos+2 {
				break
			}
			listLen := int(binary.BigEndian.Uint16(data[pos : pos+2]))
			pos += 2

			if listLen > 0 && len(data) >= pos+3 {
				nameType := data[pos]
				if nameType == 0 { // 类型0是主机名
					nameLen := int(binary.BigEndian.Uint16(data[pos+1 : pos+3]))
					pos += 3
					if len(data) >= pos+nameLen {
						return string(data[pos : pos+nameLen])
					}
				}
			}
		}

		pos += extLen
	}

	return ""
}

// 用于处理从 http 中得到的host,只返回域名，不返回其他东西
func extractPureDomain(host string) string {
	// 处理IPv6地址（如[::1]）
	if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
		return ""
	}

	// 分割主机和端口
	domain := host
	if colonIndex := strings.Index(host, ":"); colonIndex != -1 {
		domain = host[:colonIndex]
	}

	// 验证是否是有效域名（简单检查）
	if net.ParseIP(domain) != nil {
		return "" // 如果是IP地址则忽略
	}

	return domain
}
